/********************************************************************

Write Date: 2011/06/02
Author: Deng Nianchen
>>>> Add class OOPPtr to provide a stronger smart pointer utility.

Modify Date: 2011/07/16
Author: Deng Nianchen
>>>> Reimplements OOPPtrHelper to match the changes in OOPObject

*********************************************************************/
#ifndef OOP_PTR_HPP
#define OOP_PTR_HPP
#include "PtrBase.hpp"



_OOPUTILS_BEGIN


/**************************************************************************************************
 * <summary> Purpose: Helper class for OOPPtr. It's useless to create 
 * 					 an OOPPtrHelper object. So if you are not a developer, 
 * 					 just skip this class.
 * 					 Thread-Safe: the class is thread-safe. </summary>
 * 
 * <remarks>  Deng Nianchen, 2011/06/02. </remarks>
 **************************************************************************************************/

class OOPPtrHelper
{
protected:

    static inline void __increaseReference (OOPObject * pObj)
    {
        if (pObj)
            ++pObj->_pRefAffectObj->_refNum;
    }

    static inline void __decreaseReference (OOPObject * pObj)
    {
        if (pObj)
            --pObj->_pRefAffectObj->_refNum;
		_tryRelease (pObj->_pRefAffectObj);
    }

private:

    static inline void _tryRelease (OOPObject * pObj)
    {
        if (pObj && pObj->_refNum <= 0)
        {
            if (pObj->_allocInfo == OOPObject::ON_HEAP)
                delete pObj;
            else if (pObj->_allocInfo == OOPObject::ARRAY_ON_HEAP)
                delete[] pObj;
        }
    }

};

/**************************************************************************************************
 * <summary> Purpose: Encapsulate C/C++ pointer so the programmers
 * 					 didn't need to worry whether the content allocated by
 * 					 new operator has been deleted or not. This is stronger 
 * 					 pointer utility for OOPObject objects. It's more free to 
 * 					 be used than HeapPtr. No limits except that the object 
 * 					 point to must be a OOPObject or its subclass object.
 * 					 Usage: Construct a Ptr object with a pointer points to 
 * 					 an OOPObject object. Then you can use it just like normal 
 * 					 C/C++ pointer. Operators like "->", "*" is supported. 
 * 					 the pointer is also copyable. If you do not want to use it 
 * 					 and want to release the memory manually, simply assign 
 * 					 NULL to it. The memory will be recycled when there are 
 * 					 no pointers pointing to it. 
 * 					 Thread-Safe: the class is not thread-safe. </summary>
 * 
 * <remarks>  Deng Nianchen, 2011/6/2. </remarks>
 **************************************************************************************************/

template< class _Ty >
class OOPPtr : public PtrBase< _Ty >, OOPPtrHelper
{
private:

    void _refIncr ();

    void _refDecr (); 

public:

    OOPPtr ();

    OOPPtr (_Ty * newPtr) throw (NotOOPObjectException);

    OOPPtr (const OOPPtr< _Ty > & right) throw (NotOOPObjectException);

    virtual ~OOPPtr ();

    virtual OOPPtr< _Ty > & operator= (const OOPPtr< _Ty > & right );

    template< class _Ty2 >
    OOPPtr< _Ty2 > cvt () const;

};



/************************************************************************/
/* Constructors & Destructor                                            */
/************************************************************************/



template< class _Ty >
OOPPtr<_Ty>::OOPPtr () : PtrBase< _Ty > (NULL) {}



template< class _Ty >
OOPPtr<_Ty>::OOPPtr (_Ty * newPtr) throw (NotOOPObjectException)
    : PtrBase< _Ty > (newPtr)
{
    if (__pObj == NULL)
        return;
    if (dynamic_cast< OOPObject * > (__pObj) == NULL)
        OOPTHROW (NotOOPObjectException);
    _refIncr ();
}



template< class _Ty >
OOPPtr<_Ty>::OOPPtr (const OOPPtr< _Ty > & right) throw (NotOOPObjectException)
    : PtrBase< _Ty > (right.__pObj)
{
    if (__pObj == NULL) return;
    if (dynamic_cast< OOPObject * > (__pObj) == NULL)
        OOPTHROW (NotOOPObjectException);
    _refIncr ();
}



template< class _Ty >
OOPUtils::OOPPtr<_Ty>::~OOPPtr ()
{
    _refDecr ();
}



/************************************************************************/
/* Assignment Function                                                  */
/************************************************************************/



template< class _Ty >
OOPPtr< _Ty > & OOPUtils::OOPPtr<_Ty>::operator= (const OOPPtr< _Ty > & right)
{
    _refDecr ();
    __pObj = right.__pObj;
    _refIncr ();
    return *this;
}



/************************************************************************/
/* Convert Function                                                     */
/************************************************************************/



template< class _Ty >
template< class _Ty2 >
OOPPtr< _Ty2 > OOPPtr<_Ty>::cvt () const
{
    _Ty2 * pObjCvted = dynamic_cast< _Ty2 * > (__pObj);
    if (pObjCvted == NULL) {
        TypeConvertFailException e (typeid(_Ty *).name (),
                typeid(_Ty2 *).name ());
        OOPTHROW_A (e, TypeConvertFailException);
    }
    return OOPPtr< _Ty2 > (pObjCvted);
}



/************************************************************************/
/* Private Function                                                     */
/************************************************************************/



template< class _Ty >
void OOPPtr<_Ty>::_refDecr ()
{
    __decreaseReference (dynamic_cast< OOPObject * > (__pObj));
    __pObj = NULL;
}



template< class _Ty >
void OOPPtr<_Ty>::_refIncr ()
{
    __increaseReference (dynamic_cast< OOPObject * > (__pObj));
}



_OOPUTILS_END



#endif